/**
 * 
 */
package com.ordoict.smallsettlement.common.xml.loader;

import java.io.File;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.HashMap;

import javax.xml.bind.JAXBContext;

import org.apache.log4j.Logger;
import org.springframework.util.StringUtils;

import com.ordoict.smallsettlement.common.xml.entity.UnmarshallMap;
import com.ordoict.smallsettlement.common.xml.entity.UnmarshallObject;

/**
 * DESC : XML 또는 JSON 파일을 읽어서 Unmarshall하는 클래스 입니다.
 *
 * @company : OrdoICT.,Inc
 * @author  : Choi Jin Wook // choijinwook84@ordoict.com
 * @version : 1.0.0
 * @since   : 2013. 12. 9.
 * 
 */
public class Loader implements LoaderInteface{
    
    Logger logger = Logger.getLogger(this.getClass());
    
    public Loader(){}
    
    /**
     * 파일의 Path를 지정하여 객체를 생성합니다.
     * @param filePath
     */
    public Loader(String filePath){
        this.filePath = filePath;
    }

    private String filePath;
    
    /**
     * @since 2013. 12. 9.
     * @return the filePath
     */
    public String getFilePath() {
        return filePath;
    }
    
    /**
     * @since 2013. 12. 9.
     * @param filePath the filePath to set
     */
    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public HashMap<String, UnmarshallObject> getMapData() {
        
        HashMap<String, UnmarshallObject> mapData = null;
        URL url = null;
        File file = null;
        InputStream is = null;
        UnmarshallMap um = null;
        
        try {
            //map data를 생성 하니다.
            mapData = new HashMap<String, UnmarshallObject>();
            
            //URL을 가져오는 부분 입니다.
            //filePath의 지정이 'classpath:'로 시작 하는지 확인 합니다.
            if(filePath.startsWith("classpath:")){
                //'classpath:'로 시작한다면 그 부분을 잘라 냅니다.
                String path = filePath.substring("classpath:".length());
                //파일 위치를 URL로 불러 옵니다.
                url = getClass().getClassLoader().getResource(path);
                
            //filePath의 지정이 'classpath:'로 시작하지 않는다면
            }else{
                try{
                    //File Path의 URL을 불러 옵니다.
                    url = new URL(filePath);
                }catch(Exception e){
                    try{
                        //File Path의 URI로 부터 URL을 불러 옵니다.
                        url = new File(filePath).toURI().toURL();
                    }catch(Exception ie){
                        ie.printStackTrace();
                    }
                }
            }
            
            logger.debug("URL PROTOCOL : "+url.getProtocol());
            
            //URL의 파일을 읽어 옵니다.
            //URL의 Protocol이 File 인지 확인 합니다.
            if("file".equals(url.getProtocol())){
                try{
                    //URL의 경로 값을 URI 객체로 변환 하고 getSchemeSpecificPart로 파일을 File 객체로 생성합니다.
                    file = new File(new URI(StringUtils.replace(url.toString(), " ", "%20")).getSchemeSpecificPart()); 
                }catch(Exception e){
                    //URL의 File 경로로 파일을 읽어 옵니다.
                    file = new File(url.getFile());
                }
            //URL의 Protocol이 jar 인지 확인 합니다.
            }else if("jar".equals(url.getProtocol())){
                try{
                    //URI객체를 생성하여 URL로 만들고 이를 Stream 형태로 InputStream 레퍼런스 변수에 담습니다.
                    is = new URI(StringUtils.replace(url.toString(), " ", "%20")).toURL().openStream();
                }catch(Exception e){
                    file = new File(url.getFile());
                }                
            }
            
            url = null;
            
            //Unmarshalling 합니다.
            if(is != null){
                um = (UnmarshallMap) JAXBContext.newInstance(UnmarshallMap.class).createUnmarshaller().unmarshal(is);
                is.close();
                is = null;
            }else{
                um = (UnmarshallMap) JAXBContext.newInstance(UnmarshallMap.class).createUnmarshaller().unmarshal(file);
                file = null;
            }
            
            //Unmarshalling이 잘 끝나면 HashMap에 담습니다.
            if(um != null){
                for(UnmarshallObject uo : um.getObject()){
                    mapData.put(uo.getId(), uo);
                }
                um = null;
            }else{
                throw new Exception("Fail to read XML file ["+filePath+"]");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return mapData;
    }
}
